/**
 * Copyright 2008 Adam Ruggles.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package kiff.entity;

import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Transient;

import kiff.security.Permission;

import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;

/**
 * Forum Permission.
 * @author Adam
 * @version $Id: GlobalPermission.java 71 2008-11-26 21:03:06Z a.ruggles $
 */
@Embeddable
public class GlobalPermission implements Permission {
	/**
	 * Is a full administrator.
	 */
	public static final int ADMINISTRATOR = 1;

	/**
	 * Is a full moderator.
	 */
	public static final int MODERATOR = 1 << 1;

	/**
	 * Serial Version UID.
	 */
	private static final long serialVersionUID = 917374253178300989L;

	/**
	 * Permission value. The value represents 32 bits for each permission.
	 */
	private int value;

	/**
	 * Default Constructor.
	 */
	public GlobalPermission() {
		value = 0;
	}

	/**
	 * Constructor that takes a permission value.
	 * @param value the permission value to set.
	 */
	public GlobalPermission(final int value) {
		this.value = value;
	}

	/**
	 * Constructor that takes a list of values.
	 * @param values A list of values.
	 */
	public GlobalPermission(final int ... values) {
		for (int bitValue : values) {
			this.value |= bitValue;
		}
	}

	/**
	 * Adds a bit value permission using logical or.
	 * @param bitValue The bit value permission.
	 */
	public void addPermission(final int bitValue) {
		this.value |= bitValue;
	}

	/**
	 * {@inheritDoc}
	 * @see kiff.security.Permission#check(kiff.security.Permission)
	 */
	public boolean check(final Permission permission) {
		if (this == permission) {
			return true;
		}
		if (!(permission instanceof GlobalPermission)) {
			return false;
		}
		GlobalPermission rhs = (GlobalPermission) permission;
		if (rhs.getValue() == 0 && this.value != 0) {
			return false;
		}
		System.out.println("Checking bitwise permission values.");
		// Bitwise and operator to see if the given permission bits are set.
		return ((this.value & rhs.getValue()) == rhs.getValue());
	}

	/**
	 * {@inheritDoc}
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(final Object obj) {
		if (this == obj) {
			return true;
		}
		if (!(obj instanceof GlobalPermission)) {
			return false;
		}
		GlobalPermission rhs = (GlobalPermission) obj;
		return this.value == rhs.getValue();
	}

	/**
	 * Returns the permission value.
	 * @return the permission value to return.
	 */
    @Column(name = "permission")
	public int getValue() {
		return value;
	}

	/**
	 * {@inheritDoc}
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		return new HashCodeBuilder(1, 41)
			.append(value)
			.toHashCode();
	}

	/**
	 * Returns true if this permission grants the user the ability to administer the site.
	 * @return True if this permission grants the user the ability to administer the site.
	 */
	@Transient
	public boolean isAdministrator() {
		return ((this.value & ADMINISTRATOR) == ADMINISTRATOR);
	}

	/**
	 * Returns true if this permission grants the user the ability to be a global moderator for the site.
	 * @return True if this permission grants the user the ability to be a global moderator for the site.
	 */
	@Transient
	public boolean isModerator() {
		return ((this.value & MODERATOR) == MODERATOR);
	}

	/**
	 * Removes a bit value permission using logical and.
	 * @param bitValue The bit value permission.
	 */
	public void removePermission(final int bitValue) {
		this.value &= ~bitValue;
	}

	/**
	 * Sets the permission that grants the user the ability to administer the site.
	 * @param flag True to grant the permission, false to remove the permission.
	 */
	public void setAdministrator(final boolean flag) {
		if (flag) {
			addPermission(ADMINISTRATOR);
		} else {
			removePermission(ADMINISTRATOR);
		}
	}

	/**
	 * Sets the permission that grants the user the ability to be a global moderator for the site.
	 * @param flag True to grant the permission, false to remove the permission.
	 */
	public void setModerator(final boolean flag) {
		if (flag) {
			addPermission(MODERATOR);
		} else {
			removePermission(MODERATOR);
		}
	}

	/**
	 * Sets the permission value.
	 * @param value the value to set
	 */
	public void setValue(final int value) {
		this.value = value;
	}

	/**
	 * {@inheritDoc}
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		return new ToStringBuilder(this)
			.append("hex", Integer.toHexString(this.value))
			.append("administrator", (this.value & ADMINISTRATOR) == ADMINISTRATOR)
			.append("moderator", (this.value & MODERATOR) ==  MODERATOR)
			.toString();
	}
}
